I need to count the idle time of my WPF application (Idle time = when no keyboard input,mouse input (movement + clicks ) had occurred ). So far I tried 2 approaches but none of them seem to be working:
Any Other ideas? or maybe a way to modify the 2nd solution to work?
I solved the problem using a few different techniques rolled up to give me a pretty good solution. I use GetLastInput to work out when the system was last touched This is well documented elsewhere, but here's my method:
public static class User32Interop
{
public static TimeSpan GetLastInput()
{
var plii = new LASTINPUTINFO();
plii.cbSize = (uint)Marshal.SizeOf(plii);
if (GetLastInputInfo(ref plii))
return TimeSpan.FromMilliseconds(Environment.TickCount - plii.dwTime);
else
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
}
[DllImport("user32.dll", SetLastError = true)]
static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
struct LASTINPUTINFO {
public uint cbSize;
public uint dwTime;
}
}
This only tells me when the system has been idle, not the application. If the user clicks into Word and works there for an hour, I still want a timeout. To handle this case, I simply remember when my application loses focus by overriding the OnDeactivated and OnActivated methods on the application object:
override protected void OnDeactivated(EventArgs e)
{
this._lostFocusTime = DateTime.Now;
base.OnDeactivated(e);
}
protected override void OnActivated(EventArgs e)
{
this._lostFocusTime = null;
base.OnActivated(e);
}
My IsIdle routine was added to the application object. It handles the global case where the app has focus but nothing happened (IsMachineIdle) and the specific case where the application lost focus while the user is doing other stuff (isAppIdle ):
public bool IsIdle
{
get
{
TimeSpan activityThreshold = TimeSpan.FromMinutes(1);
TimeSpan machineIdle = Support.User32Interop.GetLastInput();
TimeSpan? appIdle = this._lostFocusTime == null ? null : (TimeSpan?)DateTime.Now.Subtract(_lostFocusTime.Value);
bool isMachineIdle = machineIdle > activityThreshold ;
bool isAppIdle = appIdle != null && appIdle > activityThreshold ;
return isMachineIdle || isAppIdle;
}
}
The last thing I did was create a timer loop that polled this flag event few seconds.
This seems to work fine.
Well no one seemed to answer so I continued digging and found a relatively simple solution using the OS last input + up time. the code is really simple but this solution make me do data polling which I never recommend and also instead of being in the application level it's in the OS level which is not the exact solution I needed. If someone ever opens this thread this is the code, just use GetIdleTime():
public class IdleTimeService
{
//Importing the Dll & declaring the necessary function
[DllImport("user32.dll")]
private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
/// <summary>
/// return the current idle time (in ms)
/// </summary>
/// <returns>current idle time in ms</returns>
public static int GetIdleTime()
{
//Creating the object of the structure
LASTINPUTINFO lastone = new LASTINPUTINFO();
//Initialising
lastone.cbSize = (uint)Marshal.SizeOf(lastone);
lastone.dwTime = 0;
int idleTime = 0;
//To get the total time after starting the system.
int tickCount = System.Environment.TickCount;
//Calling the dll function and getting the last input time.
if (GetLastInputInfo(ref lastone))
{
idleTime = tickCount - (int)lastone.dwTime;
return idleTime;
}
else
return 0;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With