Detecting User Inactivity
Some software, such as backup utilities, can use a large proportion of processor time and other resources. Often the user is given the option to only run such processes when the computer is not in use. This requires the detection of user inactivity.
Calculating the Inactive Time
There are several reasons why you may wish to detect when the user is idle. Some background processes are so intensive that they make all other user interaction unacceptably poor. Some software changes state when the user is inactive. For example, Windows Live Messenger can be set to set the user's status as "Away" automatically and indicate this to other systems. In these situations, and many others, the behaviour is dependant upon the length of time since the user pressed a key or moved their mouse.
In order to determine the period of inactivity, two times are required. The first is the system's up time and the second is the up time when the last user input occurred. If the second value is subtracted from the first, the duration of inactivity is known. Obtaining the first value is described in the article, "Getting the System Up Time". The time of the last user input can be obtained using a call to the Windows API using Platform Invocation Services (P/Invoke).
To follow the examples, create a new project and add a class named "InactiveTimeRetriever". As we will be using P/Invoke, ensure that you include the following using directive:
The API function that we will use to obtain the time of the last user input is GetLastInputInfo. This function uses a structure, named "LASTINPUTINFO", which must be declared as follows:
public struct LASTINPUTINFO
public uint cbSize;
public uint dwTime;
The structure has two fields. cbSize must be set to the size of the structure before GetLastInputInfo is called. dwTime will be set to the time of the last user input by the call to GetLastInputInfo. This returned value is measured in milliseconds.
With the structure defined, the GetLastInputInfo function can be added to the InactiveTimeRetriever class. Note the Boolean return value in the code below. A return value of false indicates that an error occurred whilst executing the function.
static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
Obtaining the Inactive Time
The final task is to add a method to the InactiveTimeRetriever class that will return a TimeSpan containing the duration of inactivity. The return value will be nullable, with null indicating that there was a problem when calling GetLastInputInfo.
Add the following method to the class:
public TimeSpan? GetInactiveTime()
LASTINPUTINFO info = new LASTINPUTINFO();
info.cbSize = (uint)Marshal.SizeOf(info);
if (GetLastInputInfo(ref info))
return TimeSpan.FromMilliseconds(Environment.TickCount - info.dwTime);
The method performs several actions. Firstly, a LASTINPUTINFO value is created and its size initialised. This is then passed by reference to the GetLastInputInfo function. If the function returns true, the resultant time from the dwTime field is subtracted from the system up time and transformed into a TimeSpan value, which is returned. If GetLastInputInfo fails, null is returned.
To see the method in used, download the demo and source code using the link at the top of this page. The demo shows a simple form that changes colour and shows an inactivity message when there has been no input for over five seconds.
7 February 2010