Click here to Skip to main content
15,513,793 members
Articles / Desktop Programming / Win32
Posted 22 Oct 2008


169 bookmarked

Application Idle

Rate me:
Please Sign up or sign in to vote.
4.89/5 (67 votes)
2 Mar 2009CPOL7 min read
A WinForms component to notify when your app has been idle for a specified timespan.


I recently needed to have an automatic, timed user-log-out facility in an application. I couldn't find any built-in components, so I 'Googled'. I found various suggestions but the only decent ones worked on activity system wide, not just within the application in use, so I set about writing my own. What I wanted was any key strokes or mouse movements within my application would keep the user logged in, but if none were detected for a pre-defined period, then the user would be automatically logged out.

Rejected Ideas

.NET has an event that initially looked promising, System.Windows.Forms.Application.Idle. Combined with a timer, I thought it would be the solution, but it was not suitable as there is no control over what interrupts it. For example, the timer itself causes the idle state to be exited, which makes perfect sense, of course, but excludes it for this scenario. The next obvious thing was to process key and mouse events on the main form. I rejected this as well as it would have required these to be handled individually for all controls etc... a maintenance nightmare.


In the end, I opted to use IMessageFilter's PreFilterMessage method, not to actually filter any messages, but to get notification of the ones I was interested in. This, combined with a timer, gave the functionality I needed. For convenience, I've wrapped these up into a component that you can drop onto your app's main form.

The Component

The ApplicationIdle component is very simple to use. Documentation is below but I'll cover the basics here.
This second version adds more functionality to the original but can be used in the same way. Drag it onto your form and it will appear in the component bar below the form (or just create an instance of it in your code). Set the IdleTime as required, subscribe to the Idle event and call the Start method. When the application has had no mouse or keyboard activity for the time you specified, your Idle event handling method will be raised.

The Code

The code is built around a TimeSpan _TimeRemaining that is decremented on each tick of a System.Windows.Forms.Timer timer.

The Start method sets the remaining time to the IdleTime's value, registers the component to receive application Windows Messages and starts the internal timer.

public void Start()
    if (!_IsRunning)
        _TimeRemaining = _IdleTime;
        _TimeElapsed = ZeroTime;
        _IsRunning = true;

You will notice two OnEvent methods are called at the end of this method. All the behavior events have two versions - a standard synchronous and an asynchronous one. This is in response to comments that were made on the first version.

Normally we raise events synchronously. In other words, the event doesn't return until all subscribers have done their thing in their handlers. If you decided to do something time intensive in one of your event handlers, it would block the component which isn't ideal for something that is time based like this. The answer is to raise the event asynchronously on a separate thread. The downside is, the event handling method must handle the threading properly if for example it is going to update the UI.

This is an example of how the StartedAsync event may be handled.

void applicationIdle_StartedAsync(object sender, EventArgs e)
    BeginInvoke(new MethodInvoker(
        delegate() { applicationIdle_Started(sender, e); })
void applicationIdle_Started(object sender, EventArgs e)
    // do stuff here

(For more information see my Events Made Simple article.)

When a message is received, we only need to respond to key and mouse messages. The ones we are interested in are defined in an enum ActivityMessages. All we need to do is check if the message is defined and react accordingly. Regardless of the message, we return false to indicate that we aren't actually processing the message.

bool IMessageFilter.PreFilterMessage(ref Message m)
    if (Enum.IsDefined(typeof(ActivityMessages), m.Msg))
        _TimeRemaining = _IdleTime;
        _TimeElapsed = ZeroTime;
        ActivityEventArgs e = new ActivityEventArgs((ActivityMessages)m.Msg);
    return false;

Every time the internal timer ticks, we decrease the time remaining and check if it's zero. If it is, we raise the idle events and stop the component.

private void timer_Tick(object sender, EventArgs e)
    _TimeElapsed = _TimeElapsed.Add(_TickInterval);
    _TimeRemaining = _TimeRemaining.Subtract(_TickInterval);
    // ...
    if (_TimeRemaining == ZeroTime)

When we stop the component, we need to stop the timer, reset some properties, and unregister from the application messages.

public void Stop()
    if (_IsRunning)
        _TimeRemaining = ZeroTime;
        _TimeElapsed = ZeroTime;
        _IsRunning = false;
        _IsPaused = false;

The Demo

I have included a simple demonstration application to show the component in use. Use the menu or F12 to 'Log In'. Moving/clicking the mouse or pressing a key within the application will reset the counters. Leave it idle until Remaining reads 00:00:00 and you will be automatically logged out.


That's an overview of the basics and is probably all that you will need. The next section gives an outline of all properties, events and methods of all the classes involved.

Application Idle Project Documentation

The project is a class library of the following five files. This is part of a larger component library. It builds down to Winforms.Components.dll and the component resides in the Winforms.Components namespace. Other related classes reside in the Winforms.Components.ApplicationIdleData namespace.


The WinForms component that determines whether an application has received any defined ActivityMessages for a specified TimeSpan.


Designer Visible Properties

  • IdleTime

  • A TimeSpan after which the application should be considered idle if no defined ActivityMessages are received.
  • TickInterval

  • The TimeSpan at which the component 'ticks'. Idleness is checked and appropriate events are raised on each tick.
  • WarnSetting

  • The WarnSettings value used to control warning events generation.
  • WarnTime

  • A TimeSpan at which warning events will be generated depending on the WarnSetting.

Additional Editor Visible Properties (readonly)

  • IsPaused

  • Indicates whether the component is currently paused.
  • IsRunning

  • Indicates whether the component is currently running.
  • TimeElapsed

  • A TimeSpan representing the time since the last activity was detected.
  • TimeRemaining

  • A TimeSpan representing the time until Idle assuming no activity is detected.


Property Changed Events

All the property changed events are raised when the corresponding property changes.

  • IdleTimeChanged
  • TickIntervalChanged
  • WarnSettingChanged
  • WarnTimeChanged

Synchronous Behavior Events

All the synchronous events listed below also have an asynchronous counterpart.

  • Activity

  • Raised when the component detects an activity that is defined in ActivityMessages.
  • Idle [default]

  • Raised when the IdleTime is reached.
  • Paused

  • Raised when the component is paused.
  • Started

  • Raised when the component is started.
  • Stopped

  • Raised when the component is stopped.
  • Tick

  • Raised when the component 'ticks'.
  • UnPaused

  • Raised when the component is unpaused.
  • Warn

  • May be raised when the WarnTime is reached and on each subsequent Tick depending on the WarnSetting.

Asynchronous Behavior Events

For descriptions of these events see the Synchronous Behavior Events section above.


None of the methods take any parameters.

  • GetVersion

  • Gets the assembly version of the component.
  • Restart

  • Stops, and then starts the component.
  • Start

  • Starts the component.
  • Stop

  • Stops the component.
  • TogglePause

  • Toggles the pause state of the component.


Setting IdleTime forces recalculation of TickInterval and WarnTime.
Events are fired only if the associated property changes in the following order.

  1. IdleTimeChanged
  2. TickIntervalChanged
  3. WarnTimeChanged

Setting TickInterval forces recalculation of WarnTime.
Events are fired only if the associated property changes in the following order:

  1. TickIntervalChanged
  2. WarnTimeChanged

TickInterval is forced to be a factor of the IdleTime.
WarnTime is forced to be a multiple of TickInterval and a factor of IdleTime.

IdleTime and TickInterval can only be set when the component isn't running.
Stop, Restart and TogglePause have no effect if the component isn't running.

When the component 'ticks' several events are possible. They are fired in the following order as appropriate.

  1. Tick
  2. Warn
  3. Idle
  4. Stop

All asynchronous events are fired immediately before their synchronous counterparts.


This is a simple enum of Windows messages (sourced from the winuser.h header file) that we're interested in.


This class derives from System.EventArgs and has the following property. It is used in the Activity and ActivityAsync events.

  • ActivityMessage

  • An ActivityMessages member indicating the activity that was detected.


This class derives from System.EventArgs and has the following property. It is used in the Tick and TickAsync events.


An enum used for the WarnSetting property.

  • Tick

  • Warning events are raised when the WarnTime is reached and on each subsequent Tick.
  • Once

  • Warning events are raised only when the WarnTime is reached.
  • Off

  • Warning events are not raised.


  • 22 October 2008: Initial version
  • 01 March 2009: Version 2


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Written By
CEO Dave Meadowcroft
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

QuestionPause when run Process.Start Pin
Member 1434656922-Jul-19 16:06
Member 1434656922-Jul-19 16:06 
GeneralWM_MOUSEMOVE even when no mouse movement Pin
AbsoluteGenius26-Feb-19 4:17
AbsoluteGenius26-Feb-19 4:17 
QuestionHelpfull Pin
pherschel21-Dec-18 10:32
pherschel21-Dec-18 10:32 
QuestionCompact Framework Pin
Member 135498376-Apr-18 2:49
Member 135498376-Apr-18 2:49 
QuestionNot Working Pin
niks280811-Jan-18 6:02
niks280811-Jan-18 6:02 
PraiseWorks perfectly Pin
jdsama627-Jun-17 0:04
professionaljdsama627-Jun-17 0:04 
QuestionFormulario heredado Pin
Juan Rodriguez15-Aug-15 6:04
Juan Rodriguez15-Aug-15 6:04 
AnswerRe: Formulario heredado Pin
DaveyM6924-Aug-15 6:05
professionalDaveyM6924-Aug-15 6:05 
QuestionAuto Log out feature Pin
sanjoygr812-Mar-15 20:39
sanjoygr812-Mar-15 20:39 
GeneralUseful module Pin
wbankovitch17-Dec-14 10:28
wbankovitch17-Dec-14 10:28 
GeneralExactly the component I needed. Pin
ZeedijkMike20-Sep-14 10:00
ZeedijkMike20-Sep-14 10:00 
QuestionHow can I use this in a VB.Net App? Pin
rsmldmv17-Sep-14 9:50
rsmldmv17-Sep-14 9:50 
AnswerRe: How can I use this in a VB.Net App? Pin
DaveyM6922-Sep-14 4:07
professionalDaveyM6922-Sep-14 4:07 
QuestionWindows Explorer Crashes Pin
RHBrooks19-May-14 4:47
professionalRHBrooks19-May-14 4:47 
AnswerRe: Windows Explorer Crashes Pin
DaveyM6926-May-14 4:38
professionalDaveyM6926-May-14 4:38 
QuestionGood work. Pin
clintoaug31-Mar-14 23:57
clintoaug31-Mar-14 23:57 
AnswerRe: Good work. Pin
DaveyM692-Apr-14 10:34
professionalDaveyM692-Apr-14 10:34 
GeneralRe: Good work. Pin
clintoaug2-Apr-14 21:12
clintoaug2-Apr-14 21:12 
GeneralRe: Good work. Pin
DaveyM693-Apr-14 11:18
professionalDaveyM693-Apr-14 11:18 
GeneralRe: Good work. Pin
clintoaug9-Apr-14 23:34
clintoaug9-Apr-14 23:34 
QuestionReally Cool!!!!! Pin
Nanda Rengasamy29-Oct-13 20:57
Nanda Rengasamy29-Oct-13 20:57 
QuestionExcellent article. Pin
muralikrishnagangineni15-Mar-13 6:31
muralikrishnagangineni15-Mar-13 6:31 
GeneralMy vote of 5 Pin
Bkins6-Jul-12 14:02
Bkins6-Jul-12 14:02 
GeneralRe: My vote of 5 Pin
DaveyM6910-Jul-12 12:34
professionalDaveyM6910-Jul-12 12:34 
QuestionApplication Idle Pin
habay4lordcom18-Jun-12 5:15
habay4lordcom18-Jun-12 5:15 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.