【问题标题】:.NET: How to get time for keypress as precisely as possible?.NET:如何尽可能准确地获得按键时间?
【发布时间】:2015-03-17 08:06:16
【问题描述】:

我正在尝试构建一个通常不必具有超级性能的应用程序,除了键盘按下(或外部控制器按钮按下)的时间戳。我希望时间戳尽可能精确,最好是 +/- 5ms。这是为了科学应用。以最小延迟实现这一目标的最佳编程范例是什么?以下哪一项更可取?

(a) 创建一个以更高优先级运行的工作线程并循环查看是否按下了某个键。使用Sleep(x),其中x 小于5。

(b) 创建一个键盘钩子,它有一个异步回调。

(c) 另一种选择。

除了答案之外,任何代码(或示例链接)都将不胜感激,因为我是一个相当新的开发人员。

编辑:命名法。应该更加小心。通过时间戳,我的意思是一般的时间,不一定是完整的日月年时分秒毫秒。我从一开始就计划使用 StopWatch 类,因为我需要的只是程序中事件开始和按下按钮之间的时间。抱歉,如果不清楚。

【问题讨论】:

  • 您是在寻找真正的时间戳(一个时间点),还是只是次按键之间的时间?
  • 我正在寻找事件开始和按键之间的区别。我计划使用秒表类。不确定是否推荐。
  • this question 已经很好地介绍了。非常怀疑 Stopwatch 是否会为您做任何事情,如果确实如此,那么您没有很好地解释您的要求。

标签: c# xna keyboard keyboard-events low-latency


【解决方案1】:

如果您正在寻找按键的确切时间戳,则 DateTime 可能不是您想要使用的:

Get DateTime.Now with milliseconds precision

DateTime 具有很高的精度,但在 准确性。一般来说,你不能。通常是系统时钟 (这是 DateTime.Now 从中获取数据的地方)的分辨率为 大约 10-15 毫秒。请参阅 Eric Lippert 关于精度和 更多细节的准确性。

如果您需要比这更准确的时间,您可能需要查看 使用 NTP 客户端。

以及该帖子中的引用链接:

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

现在,问题是“从开始到结束经过了多少时间?”是 与“现在几点了?”完全不同的问题。如果 你想问的问题是一些操作需要多长时间, 并且您想要一个高精度、高精度的答案,然后使用 StopWatch 班级。它确实具有纳秒级的精度和准确度 这接近于它的精度。

记住,你不需要知道现在几点才能知道多少时间 已经过去。这可能是完全不同的两件事。

【讨论】:

  • 我曾计划使用秒表。哪种范例最适合使用秒表?
  • “范式”是什么意思?这是使用StopWatch 类的不错的基本介绍:dotnetperls.com/stopwatch
  • 我想我的意思是同步或异步模式,(a)或(b),或者我没有想到的第三种选择。
【解决方案2】:

来自 cmets:

我正在寻找事件开始和按键之间的区别。

了解这与尝试获取按键的实际时间戳非常不同,这一点很重要。

这种情况正是Stopwatch 的用途。是的,使用它并感谢您并没有真正尝试获取时间戳。

在事件开始时使用Stopwatch.StartNew,在按键事件中使用Stopwatch.Stop。事件处理程序触发有轻微的延迟,但与其他任何事情相比,这将是很小的 - 如果它在这里给您带来任何问题,我会感到惊讶。

【讨论】:

  • 那么您认为使用事件处理程序而不是使用同步模式更明智?
  • @Doug:是的 - 我自己没有使用过 XNA,但我希望它像大多数 UI 一样基于事件。
  • @Doug 不确定,但我认为说“事件处理程序,而不是同步模式”是不对的。事件是同步的,除非您竭尽全力使它们异步。 stackoverflow.com/questions/7106454/…
【解决方案3】:

DateAndTime.Timer 是最准确的。它返回一个双精度浮点数,表示从午夜经过的秒数。

用法(在 VB 中):

x# = DateAndTime.Timer

'... some code...

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

【讨论】:

    【解决方案4】:

    如果你最终使用了一个循环,这是一个优于我测试过的所有其他循环的循环 ->

    <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
    

    但如果您使用的是外部控制器而不是键盘,那么我想您应该调用 GetQueueStatus 而不是 GetInputState...

    【讨论】:

      猜你喜欢
      • 2015-01-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多