How to detect application idle time.

  • Thread starter Thread starter Frank Rizzo
  • Start date Start date
F

Frank Rizzo

I want to log the user out when there has been a period of inactivity in
the application. The key here is inactivity of the application, not the
system. I know that you can retrieve the inactivity of the system via
GetLastInputInfo. That's not what I want - I want inactivity of the
application.

Thanks.
 
You can use a global Timer in your application and restart it when the user
takes any action. You must be sure that any action of the user will restart
the Timer. If the Timer_Tick events goes, you know the application
inactivity time.
It's only a suggestion.

Ernesto Lores
 
cody said:
Use static event Application.Idle

I tried, but it seems to fire all the time (even when a timer event is
processed) and the arguments are empty.
 
ShaneB said:
How are you coming to the conclusion that it is firing too much?

I write to the log everytime it fires. So everytime, I move a mouse or
use a keyboard or a timer event fires, the Idle event goes off. I could
live with it, however, I have a bunch of timers in the application.
 
This is normal behaviour for the Application.Idle event. As soon as the
application's message queue is empty, the event is fired. This means that
after each mouse movement, timer event, keypress, etc...you get this event.
That's because the message queue got a message in it, processed it, and now
it is empty again. Remember, most applications spend 99% of their time in
an idle state...waiting on us. You will get tons of these messages during
the life of your application

What exactly are you trying to do at idle?

ShaneB
 
Apparently you need to merge the two suggestions on the table. First, since
Idle fires when your message queue is exhausted, then you should hook that
because it identifies the moment immediately following all user input having
been processed... In the idle event, reset your timer so that it restarts. If
your
timer fires an event, then you can assume the user has been idle for some
period of time.

You have to be careful with this, since exhausting the message queue is
required. You can hook into an LRO or long running operation that allows
your timer to expire. Another option is to hook up a message filter and
examine messages as they come through. This allows you to stop the timer
when you see an operation getting ready to start, followed by starting it
again when the idle event hits.
 
Here's one way to accomplish what you want. I'm be interested if someone
comes up with a better one. Application.Idle being a static event makes
this task a little more complicated than it had to be.

Anyway, you should be able to cut/paste the code below directly into an
empty project in place of the default Form1.cs and it should run fine.

ShaneB



using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace MyApp
{
public class Form1 : System.Windows.Forms.Form, IMessageFilter //
note that we're implementing IMessageFilter because we want the see all
messages coming in.
{
private System.Windows.Forms.Timer timer1;
private System.ComponentModel.IContainer components;
private static int iEnteredIdleTicks; // we need a static
variable since Application.Idle is a static event.

public Form1()
{
InitializeComponent();
}

protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.timer1 = new
System.Windows.Forms.Timer(this.components);
this.timer1.Enabled = true; // the timer will always be
running
this.timer1.Interval = 60000; // we'll check every 60
seconds to see if the application has been idle too long
this.timer1.Tick += new
System.EventHandler(this.timer1_Tick_1);

this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.Name = "Form1";
}

[STAThread]
static void Main()
{
Application.Idle += new EventHandler(Application_Idle); // we
want to process Idle events
Application.Run(new Form1());
}

private static void Application_Idle(object sender, EventArgs e)
{
iEnteredIdleTicks = Environment.TickCount;
}

private void timer1_Tick_1(object sender, System.EventArgs e)
{
if ( (iEnteredIdleTicks != 0) && (Environment.TickCount -
iEnteredIdleTicks > 300000) )
// In the above line, my test timeout value is 300 seconds (5
minutes). Note that depending on when the timer event is fired, this could
effectively be as long as 5 minutes + the timer1.Interval.
{
timer1.Enabled = false; // Prevents any further timer
messages...just in case.
// <you would log off the user here>
Application.Exit();
}
}

public bool PreFilterMessage(ref Message m)
{
iEnteredIdleTicks = 0; // reset our ticks since we got a new
message to handle...ie, we're no longer idling.
return false;
}
}
}
 
Use the Process class. You can check for an Idle property when you start
your app through the process 'p' object.

Process p=new Process();


with regards,


J.V.Ravichandran
- http://www.geocities.com/
jvravichandran
- http://www.411asp.net/func/search?
qry=Ravichandran+J.V.&cob=aspnetpro
- http://www.southasianoutlook.com
- http://www.MSDNAA.Net
- http://www.csharphelp.com
- http://www.poetry.com/Publications/
display.asp?ID=P3966388&BN=999&PN=2
- Or, just search on "J.V.Ravichandran"
at http://www.Google.com
 
That's what I have, Shane. However, the problem is that the Timer event
itself causes the Idle event to be fired. How are you addressing that?
 
Ahh...excellent point. Change the following:

public bool PreFilterMessage(ref Message m)
{
const int WM_TIMER = 275;
if (m.Msg != WM_TIMER)
{
iEnteredIdleTicks = 0;
}
return false;
}

ShaneB
 
Maybe you should use a non "windows message" based timer like
System.Timers.Timers or System.Threading.Timer.

Willy.

Frank Rizzo said:
That's what I have, Shane. However, the problem is that the Timer event
itself causes the Idle event to be fired. How are you addressing that?
Here's one way to accomplish what you want. I'm be interested if someone
comes up with a better one. Application.Idle being a static event makes
this task a little more complicated than it had to be.

Anyway, you should be able to cut/paste the code below directly into an
empty project in place of the default Form1.cs and it should run fine.

ShaneB



using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace MyApp
{
public class Form1 : System.Windows.Forms.Form, IMessageFilter //
note that we're implementing IMessageFilter because we want the see all
messages coming in.
{
private System.Windows.Forms.Timer timer1;
private System.ComponentModel.IContainer components;
private static int iEnteredIdleTicks; // we need a static
variable since Application.Idle is a static event.

public Form1()
{
InitializeComponent();
}

protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.timer1 = new
System.Windows.Forms.Timer(this.components);
this.timer1.Enabled = true; // the timer will always
be running
this.timer1.Interval = 60000; // we'll check every 60
seconds to see if the application has been idle too long
this.timer1.Tick += new
System.EventHandler(this.timer1_Tick_1);

this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.Name = "Form1";
}

[STAThread]
static void Main()
{
Application.Idle += new EventHandler(Application_Idle); //
we want to process Idle events
Application.Run(new Form1());
}

private static void Application_Idle(object sender, EventArgs e)
{
iEnteredIdleTicks = Environment.TickCount;
}

private void timer1_Tick_1(object sender, System.EventArgs e)
{
if ( (iEnteredIdleTicks != 0) && (Environment.TickCount -
iEnteredIdleTicks > 300000) )
// In the above line, my test timeout value is 300 seconds (5
minutes). Note that depending on when the timer event is fired, this
could effectively be as long as 5 minutes + the timer1.Interval.
{
timer1.Enabled = false; // Prevents any further timer
messages...just in case.
// <you would log off the user here>
Application.Exit();
}
}

public bool PreFilterMessage(ref Message m)
{
iEnteredIdleTicks = 0; // reset our ticks since we got a
new message to handle...ie, we're no longer idling.
return false;
}
}
}
 
My keyboard is not working. SO, add the open close parentheses as
applicable.

using System.Diagnostics;
....
Process p=new Process);
ProcessStartInfo pf=new ProcessStartInfo"Application name");
p.StartInfo=pf;
p.Start;
if p.Responding
{
// the process is responding.
}

I hope the above solves your problem.

with regards,


J.V.Ravichandran
- http://www.geocities.com/
jvravichandran
- http://www.411asp.net/func/search?
qry=Ravichandran+J.V.&cob=aspnetpro
- http://www.southasianoutlook.com
- http://www.MSDNAA.Net
- http://www.csharphelp.com
- http://www.poetry.com/Publications/
display.asp?ID=P3966388&BN=999&PN=2
- Or, just search on "J.V.Ravichandran"
at http://www.Google.com
 
I believe the original poster is trying to detect idle time from within the
same application. Similar to how windows 2000/Xp/Nt locks the computer if
you're away for a too long (if you have it set up that way). Regardless,
the method below only indicates if the application is too busy to answer a
message or is locked up. It has nothing to do with whether it is idle or
not.

ShaneB
 
Back
Top