- Use 32-bit Environment.TickCount with unchecked uint arithmetic so GetIdleTime stays correct after the ~49.7 day uint wrap boundary - Only clear _pausedTaskId after successful resume, not before the API call - Add retry path: if resume failed, retry on next poll cycle while user is still active Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
36 lines
1.1 KiB
C#
36 lines
1.1 KiB
C#
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
|
|
namespace WindowWatcher;
|
|
|
|
internal static partial class NativeMethods
|
|
{
|
|
[LibraryImport("user32.dll")]
|
|
internal static partial IntPtr GetForegroundWindow();
|
|
|
|
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
|
internal static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
|
|
|
|
[LibraryImport("user32.dll", SetLastError = true)]
|
|
internal static partial uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
internal struct LASTINPUTINFO
|
|
{
|
|
public uint cbSize;
|
|
public uint dwTime;
|
|
}
|
|
|
|
[DllImport("user32.dll")]
|
|
internal static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
|
|
|
|
internal static TimeSpan GetIdleTime()
|
|
{
|
|
var info = new LASTINPUTINFO { cbSize = (uint)Marshal.SizeOf<LASTINPUTINFO>() };
|
|
if (!GetLastInputInfo(ref info))
|
|
return TimeSpan.Zero;
|
|
// Use 32-bit TickCount so both values wrap at the same boundary as dwTime (uint)
|
|
return TimeSpan.FromMilliseconds(unchecked((uint)Environment.TickCount - info.dwTime));
|
|
}
|
|
}
|