Programmatically determining whether a Windows user is idle

An overview of how to determine if a Windows user is idle by checking when they last interacted with the PC (using the Win32 GetLastInputInfo API).


I recently had a contract to develop some Windows software that needed to track when the user had stopped using the PC. There are a few ways of doing this, but one of the easiest and best is by using the Win32 GetLastInputInfo function. This function tells us when the last user input event (keyboard or mouse) occurred.

I built a simple C# wrapper around this functionality, allowing easy access to:

  1. The time at which the last user input event occurred.
  2. How long it has been since the last user input event.

The code is as follows:

public static class InputTimer
{
    public static TimeSpan GetInputIdleTime()
    {
        var plii = new NativeMethods.LastInputInfo();
        plii.cbSize = (UInt32)Marshal.SizeOf(plii);

        if (NativeMethods.GetLastInputInfo(ref plii))
        {
            return TimeSpan.FromMilliseconds(NativeMethods.GetTickCount64() - plii.dwTime);
        }
        else
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }
    }

    public static DateTimeOffset GetLastInputTime()
    {
        return DateTimeOffset.Now.Subtract(GetInputIdleTime());
    }
    
    private static class NativeMethods
    {
        public struct LastInputInfo
        {
            public UInt32 cbSize;
            public UInt32 dwTime;
        }

        [DllImport("user32.dll")]
        public static extern bool GetLastInputInfo(ref LastInputInfo plii);

        [DllImport("kernel32.dll")]
        public static extern uint GetTickCount();
    }
}

The code can be used as follows:

Console.WriteLine($"Current time: {DateTimeOffset.Now}");
Console.WriteLine($"Last input time: {InputTimer.GetLastInputTime()}");
Console.WriteLine($"Idle time: {InputTimer.GetInputIdleTime()}");

Note that this code uses the system tick count, which is represented as an unsigned 32-bit int, and will thus reset to 0 every 49.7 days of continuous system uptime. Please consider this when determining if this code is suitable for your purposes.

Hopefully this code helps you if you ever need to do something similar yourself.


Posted by Matthew King on 18 August 2018
Permission is granted to use all code snippets under CC BY-SA 3.0 (just like StackOverflow), or the MIT license - your choice!