Ich löste das Problem ein paar verschiedene Techniken aufgerollt, um mir eine ziemlich gute Lösung. Ich benutze GetLastInput heraus zu arbeiten, wenn das System das letzte Mal war gerührt Dieses gut an anderer Stelle dokumentiert ist, aber hier ist meine Methode:
public static class User32Interop
{
public static TimeSpan GetLastInput()
{
var plii = new LASTINPUTINFO();
plii.cbSize = (uint)Marshal.SizeOf(plii);
if (GetLastInputInfo(ref plii))
return TimeSpan.FromMilliseconds(Environment.TickCount - plii.dwTime);
else
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
}
[DllImport("user32.dll", SetLastError = true)]
static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
struct LASTINPUTINFO {
public uint cbSize;
public uint dwTime;
}
}
Das bin ich nur erzählt, wenn das System im Leerlauf war, nicht die Anwendung. Wenn der Benutzer in Word klickt und dort für eine Stunde arbeitet, möchte ich immer noch eine Zeitüberschreitung. Um diesen Fall zu behandeln, ich erinnere mich nur, wenn meine Anwendung den Fokus verliert durch die OnDeactivated zwingende und OnActivated Methoden auf dem Anwendungsobjekt:
override protected void OnDeactivated(EventArgs e)
{
this._lostFocusTime = DateTime.Now;
base.OnDeactivated(e);
}
protected override void OnActivated(EventArgs e)
{
this._lostFocusTime = null;
base.OnActivated(e);
}
Meine IsIdle Routine wurde auf das Anwendungsobjekt hinzugefügt. Es behandelt den globalen Fall, dass der App des Fokus hat, aber es ist nichts passiert (IsMachineIdle) und den speziellen Fall, wo die Anwendung des Fokus verloren, während der Benutzer andere Dinge tut (isAppIdle):
public bool IsIdle
{
get
{
TimeSpan activityThreshold = TimeSpan.FromMinutes(1);
TimeSpan machineIdle = Support.User32Interop.GetLastInput();
TimeSpan? appIdle = this._lostFocusTime == null ? null : (TimeSpan?)DateTime.Now.Subtract(_lostFocusTime.Value);
bool isMachineIdle = machineIdle > activityThreshold ;
bool isAppIdle = appIdle != null && appIdle > activityThreshold ;
return isMachineIdle || isAppIdle;
}
}
Das letzte, was ich tat, war, erstellen eine Timer-Schleife, die dieses Flag-Ereignis einige Sekunden lang abfragt.
Dies scheint gut zu funktionieren.
Denken Sie daran, _lostFocusTime sollte als DateTime deklariert werden? Variable. Wenn Sie versuchen, DateTime zu deklarieren, können Sie den Wert nicht NULLEN. – Saren
Environment.TickCount hat den Typ int und muss alle 24,9 Tage umbrechen. LASTINPUTINFO.dwTime hat den Typ "uint", daher wird es erst nach 49,7 Tagen umgebrochen. Wenn die Maschine länger als 24,9 Tage eingeschaltet war, dann ist die Mathematik im Beispiel vermasselt. Ich habe das Problem gemildert, indem ich Environment.TickCount durch einen Aufruf der WINAPI-Funktion GetTickCount ersetzt habe, die ebenfalls einen uint-Wert zurückgibt.Ich bin mir nicht sicher, was passiert, wenn die letzte Eingabe bei 49,5 Tagen und die aktuelle Tickzahl bei 50,0 Tagen liegt. [Nach dieser Antwort auf eine andere Frage] (http://stackoverflow.com/a/1078089/2998072) sollte es in Ordnung sein. –