I rozwiązać problem przy użyciu kilku różnych technik zwinięte dać mi całkiem dobre rozwiązanie. Używam GetLastInput wypracować gdy system został ostatni dotknął ten jest dobrze udokumentowany gdzie indziej, ale tutaj jest moja metoda:
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;
}
}
To tylko mówi mi, gdy system jest bezczynny, a nie aplikacji. Jeśli użytkownik kliknie w program Word i będzie tam pracować przez godzinę, nadal oczekuję limitu czasu. Aby obsłużyć ten przypadek, po prostu pamiętam, kiedy moja aplikacja traci ostrość poprzez nadpisanie OnDeactivated i OnActivated metod na obiekcie aplikacji:
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);
}
Moja IsIdle rutyna została dodana do obiektu aplikacji. Obsługuje globalny przypadek, w którym aplikacja ma skupić, ale nic się nie stało (IsMachineIdle) oraz szczególnym przypadku, gdy aplikacja stracił ostrość, gdy użytkownik robi inne rzeczy (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;
}
}
Ostatnią rzeczą, jaką zrobiłem było stworzenie pętla timera, która odpytała to zdarzenie flagowe kilka sekund.
To wydaje się działać prawidłowo.
Należy pamiętać, _lostFocusTime należy zadeklarować jako DateTime? zmienna. Jeśli próbujesz zadeklarować jako DateTime, nie możesz NULL wartość out. – Saren
Środowisko.TickCount ma typ int i jest zmuszany do owijania co 24,9 dni. LASTINPUTINFO.dwTime ma typ Uint, więc nie jest zawijany do 49,7 dni. Jeśli maszyna była włączona przez ponad 24,9 dni, to matematyka w tym przykładzie została skręcona. Zmniejszyłem problem, zamieniając Environment.TickCount na wywołanie funkcji WINAPI GetTickCount, która również zwraca wartość uint.Nie jestem pewien, co się stanie, jeśli ostatnie wejście trwało 49,5 dnia, a aktualna liczba pasków wynosi 50,0 dni. [Zgodnie z tą odpowiedzią na inne pytanie] (http://stackoverflow.com/a/1078089/2998072) powinno być OK. –