Improve company productivity with a Business Account.Sign Up

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 463
  • Last Modified:

Detecting system idleness

In C#, how do I do the following:

I need to popup a certain window and play a sound when some event occurs. And this should happen ONLY when the user is actively using the system. One idea is to listen for mouse or keyboard events and decide based on when it was last moved / pressed.  In this case, I might probably catch the cases where the user is logged on but not using the system at all (for example if the screensaver is running).  But I'll not be able to detect the case when the PC is locked by the user (the user might lock his windows account with ctrl-alt-del and still move his mouse...  in this case, hes not actually looking at his desktop so this is not the right time for my window to popup).

Can someone tell me the best way to check system idleness?
0
v_karthik
Asked:
v_karthik
  • 6
  • 6
1 Solution
 
cookreCommented:
I honestly don't recall if LastInputInfo() reflects fiddling while the desktop is locked.  If it does, this may help out:

// ///////////////////////////////////////////////////////
// /////////////////////////////////////////////////////// GetLogonDesktopState
// ////////////////////////////////////////////////////////////////////////////
void GetLogonDesktopState()
{
LogonDesktopState=0;

IntPtr DeskTopHandle=(IntPtr)null;
try {
    DeskTopHandle=OpenDesktop("Winlogon",0,true,(long)0x41); // 41=enum & read
    }
catch (Exception e)
      {
      PutMsg("WinLogon open excp <"+e.ToString()+">");
      return;
      }
if (DeskTopHandle==IntPtr.Zero)
   {
   PutMsg("Unable to open Winlogon ("+GetLastError().ToString()+")");
   return;
   }
EnumDesktopWindows(DeskTopHandle,new EnumWinProc(EnumLogonWindows),0);
CloseDesktop(DeskTopHandle);
return;
}

// ///////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////// EnumLogonWindows
// ////////////////////////////////////////////////////////////////////////////
bool EnumLogonWindows(int hwnd,int lParam)
{
windowHandle=(IntPtr)hwnd;

StringBuilder sb=new StringBuilder(1024);
GetWindowText((int)windowHandle,sb,sb.Capacity);
if (sb.Length>0)
   {
   if (sb.ToString()=="Windows Security") {LogonDesktopState=1; return false;}
   if (sb.ToString()=="Computer Locked")  {LogonDesktopState=2; return false;}
   if (sb.ToString()=="Unlock Computer")  {LogonDesktopState=3; return false;}
   }
return true;
}








//
// Unfortunately, the screensaver and computer locked screens frequently
// switch back and forth without user action, to wit, on an idle box, the
// screensaver starts, runs for a while and is then replaced with the
// computer locked screen, which is later replaced with the screen saver,
// ad nauseum.
//
// Now, since our main concern in the reboot event is user activity, we
// won't consider a change fron ss running to the locked screen (or the
// reverse) as a user caused change in state.

GetLogonDesktopState();
if (IsSSRunning()) SSState=1;
              else SSState=0;

// Presume effective state change
StateChg=true;

// Now see if there really wasn't one
if ((PrevLogonDesktopState==LogonDesktopState) && (PrevSSState==SSState))
   {
   StateChg=false;
   }
else
   {
   if (   (   PrevLogonDesktopState==0   // Computer Locked wasn't visible
           && LogonDesktopState==2       // but now it is
           && PrevSSState==1             // and the screensaver went from running
           && SSState==0)                // to not running
                                         // OR
       || (   PrevLogonDesktopState==2   // Computer Locked was visible
           && LogonDesktopState==0       // but now it isn't
           && PrevSSState==0             // an the screensaver went from not running
           && SSState==1))               // to runing
      {
      StateChg=false;                    // Then that's not a real change.
      }
   }

// Tally what we found out
if (LogonDesktopState!=PrevLogonDesktopState) PrevLogonDesktopState=LogonDesktopState;
if (SSState!=PrevSSState) PrevSSState=SSState;
if (StateChg) MostRecentLogonDesktopStateChg=System.DateTime.Now;


0
 
v_karthikAuthor Commented:
thanks .. i'll try this out... but im afraid i understand only part of it. especially i dont understand the last part (i assume thats what tells me how to trigger my function when the user is actively using the PC) ... would u be able to give me a snippet that shows a MessageBox when the user is using the system?
0
What Kind of Coding Program is Right for You?

There are many ways to learn to code these days. From coding bootcamps like Flatiron School to online courses to totally free beginner resources. The best way to learn to code depends on many factors, but the most important one is you. See what course is best for you.

 
cookreCommented:
Before worrying about the provided code, run a test first to see if LastInputInfo() shows input when the desktop is locked.  If it doesn't, then that's all you need.
0
 
v_karthikAuthor Commented:
OK. I'll test it and get back to u. Thanks.
0
 
v_karthikAuthor Commented:
I tested it, and it does seem to detect input even when the desktop is locked.. so I need some other way to do this. I got this from microsoft site
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shutdown/base/lockworkstation.asp

It says,
"There is no function you can call to determine whether the workstation is locked. To verify whether it is worth attempting to update your user interface, you can test whether or not your window is visible. This also has the advantage of identifying when the user cannot see your user interface because it is obscured by another window, minimized, or offscreen."

I tried this IsWindowVisible api call, but it doesnt seem to work well for me. It always returns true (visible) even if I minimize it, hide it under other windows or lock the desktop.

If I have some other alternative to check if window is visible, I can try coupling it with lastinputinfo.
0
 
cookreCommented:
First, make sure the screen saver isn't running:

bool IsSSRunning()
{
IntPtr SSDeskTopHandle=(IntPtr)null;
try {
    SSDeskTopHandle=OpenDesktop("Screen-Saver",0,true,(long)0x41); // 41=enum & read
    }
catch // (Exception e)
      {
      // Nope
      }
if (!(SSDeskTopHandle==(IntPtr)null))
   {
   CloseDesktop(SSDeskTopHandle);
   Yup
   }
Nope



If it's not, make sure the desktop isn't:
   * pending lock (they just hit CtrlAltDel)
   * locked
   * pending unlock (it was locked, but some input occured)

See getLogonDesktopState() above.

It opens the logon desktop then looks for any of three windows.  If none of the three is found, the user desktop isn't locked.
0
 
v_karthikAuthor Commented:
With whatever I understood, I tried this ... I ran a test appln that checks every second if the computer is unlocked or locked and prints the result. I started getting "unlocked" messages, which was fine. I locked the computer, waited for a few seconds and logged in back. There was no "locked" message, all I saw was "unlocked".
0
 
v_karthikAuthor Commented:
http://blogs.msdn.com/shawnfa/archive/2005/05/17/418891.aspx?CommentPosted=true#commentmessage

I've tested the above, works like charm.  

Now, if I combine this and lastinputinfo, can I be sure that I cover all the cases? That is, Lastinputtime returns value close to current time, and if the machine is not locked, can I assume that the user is using the machine? Can you think of any other case that I've overlooked?
0
 
cookreCommented:
The only other thing I can think of are game controllers, MIDI devices, and non-standard input devices like touch screens and pens.  The non-standard input devices are likely on dedicated boxes you won't be running on, and you probably don't want to interrupt someone in the middle of using the first two.

And thank you for the link - I've several services I can clean up with that method.
0
 
v_karthikAuthor Commented:
Thanks, that shouldnt be a big problem for my app I guess.

No problem. I'm going to accept ur answer, but one slightly unrelated question. Using the link I gave above, and also adding a timer to periodically check lastinputinfo, I thought of implementing a usercontrol so that I can share it with others if it comes out fine.

I used the user control wizard and added the code. All this is fine. Now when I actually add the control to an application (a form), the control doesnt seem to have a distinguishing background. That is, if I drag drop the control on the form, it kinda merges with the form and it becomes hard for me to locate the control later. I was wondering how to make it appear like the timer control (which resides below the form when u drag drop it). Or atleast, even if it resides on the form, I want it to appear like an icon or something so that I don't have to click all over the form to find it.  Do u have any input on this? I know this isnt related to my original q and this may not be very important, but I don't want the control to look too amateurish.
0
 
cookreCommented:
Alas, I've never written any controls - I'm just a writer of low level system utilities.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

What Kind of Coding Program is Right for You?

There are many ways to learn to code these days. From coding bootcamps like Flatiron School to online courses to totally free beginner resources. The best way to learn to code depends on many factors, but the most important one is you. See what course is best for you.

  • 6
  • 6
Tackle projects and never again get stuck behind a technical roadblock.
Join Now