4

我想检查我的应用程序中的用户不活动。我做了一些研究并选择使用 GetLastInputInfo 和 Environment.TickCount 因为它看起来很简单。不幸的是,事实证明它有点敏感。

GetLastInputInfo 返回一个LASTINPUTINFO结构,该结构具有最后一个“TickCount”值作为 DWORD(即 UInt32)。理论上,我想从 Environment.TickCount 中减去该值,这给了我用户处于非活动状态的毫秒数。

Environment.TickCount 返回一个 Int32。当它们达到最大值时,两者都会环绕,这对于 Int32 和 UInt32 是不同的。处理这个我有点不舒服,特别是因为代码基本上无法测试(Environment.TickCount 会在 24.9 天后环绕,并且该功能在此之前到期)。

这是我到目前为止所做的:

[DllImport("user32.dll")]
static extern bool GetLastInputInfo(out LastInputInfo plii);
struct LastInputInfo
{
  public uint cbSize;
  public uint dwTime;
}

//(...)
var lastInputInfo = new LastInputInfo();
lastInputInfo.cbSize = (uint)Marshal.SizeOf(lastInputInfo);
if (GetLastInputInfo(out lastInputInfo))
{
  // The next line obviously will not work when either of the terms has wrapped around
  var idleTime = Environment.TickCount - lastInputInfo.dwTime;
  if (idleTime > mTimeOut)
  {
    // user is inactive!
  }
}

是否有一种足够简单的方法来处理这两种环绕,或者我应该使用另一种方法来完全检测用户的不活动?此外,对于如何在不使用计算机 25 天的情况下进行测试的任何建议,我们将不胜感激。

4

2 回答 2

7

由于不活动的时间比滴答计数器的容量要小得多,所以这根本不是问题。

如果其中一个计数器已环绕而不是另一个,则减法中的结果也将环绕并为您提供正确的结果。您只需要转换这些值,以便它们是相同的数据类型:

int idleTime = Environment.TickCount - (int)lastInputInfo.dwTime;

例如,如果Environment.TickCount绕到 -2147483612 并且 lastInputInfo.dwTime 为 2147483624,则 -2147483612 - 2147483624 = 60。

您甚至可以将这两个值转换为较小的数据类型,例如 Int16,只要空闲时间适合数据类型,在减法之后您仍然会得到正确的结果。

于 2012-06-27T17:09:12.707 回答
4

这只是对 Guffa 答案的补充。

依靠整数溢出始终使用unchecked关键字是“最佳实践”。有两个原因:

  1. 它让读者知道你故意依赖溢出
  2. 虽然未选中是 C# 中的默认设置,但可以在编译器的命令行上进行更改。

选中和未选中(C# 参考)

int idleTime = unchecked(Environment.TickCount - (int)lastInputInfo.dwTime);
于 2012-06-27T18:44:15.330 回答