Created
October 1, 2021 14:26
-
-
Save jnm2/245e67a574cc8af2ddaeaf97e06a1bb9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Csproj: <PackageReference Include="Microsoft.Windows.CsWin32" Version="0.1.588-beta" PrivateAssets="all" /> | |
// NativeMethods.txt: GetLastInputInfo | |
using System; | |
using System.Threading; | |
using Windows.Win32; | |
using Windows.Win32.UI.KeyboardAndMouseInput; | |
public sealed class InactivityWatcher : IDisposable | |
{ | |
private readonly TimeSpan inactivityDuration; | |
private readonly Timer timer; | |
private bool stopOrStartWasCalled; | |
public event EventHandler Inactive; | |
public InactivityWatcher(TimeSpan inactivityDuration) | |
{ | |
this.inactivityDuration = inactivityDuration; | |
timer = new(OnTimerCallback); | |
} | |
public void Dispose() => timer.Dispose(); | |
public void Restart() | |
{ | |
stopOrStartWasCalled = true; | |
timer.Change(dueTime: inactivityDuration, period: Timeout.InfiniteTimeSpan); | |
} | |
public void Stop() | |
{ | |
stopOrStartWasCalled = true; | |
timer.Change(dueTime: Timeout.InfiniteTimeSpan, period: Timeout.InfiniteTimeSpan); | |
} | |
private unsafe void OnTimerCallback(object state) | |
{ | |
// Workaround for https://github.com/microsoft/win32metadata/issues/683#issuecomment-931662592 | |
var lastInputInfo = new LASTINPUTINFO { cbSize = (uint)sizeof(LASTINPUTINFO) }; | |
if (!PInvoke.GetLastInputInfo(&lastInputInfo)) | |
{ | |
Restart(); | |
return; | |
} | |
var timeSinceLastInputEvent = TimeSpan.FromMilliseconds(Environment.TickCount - lastInputInfo.dwTime); | |
if (timeSinceLastInputEvent < inactivityDuration) | |
{ | |
timer.Change(dueTime: inactivityDuration - timeSinceLastInputEvent, period: Timeout.InfiniteTimeSpan); | |
return; | |
} | |
stopOrStartWasCalled = false; | |
try | |
{ | |
Inactive.Invoke(this, EventArgs.Empty); | |
} | |
finally | |
{ | |
if (!stopOrStartWasCalled) Restart(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment