Jump to content


Check out our Community Blogs

Register and join over 40,000 other developers!


Recent Status Updates

View All Updates

Photo
- - - - -

Detect User Idle And Do Something After Some Time Ellapsed, Part 2: System-Wide User Idle Detection

timer

  • Please log in to reply
No replies to this topic

#1 Luthfi

Luthfi

    CC Leader

  • Expert Member
  • PipPipPipPipPipPipPip
  • 1320 posts
  • Programming Language:PHP, Delphi/Object Pascal, Pascal, Transact-SQL
  • Learning:C, Java, PHP

Posted 03 May 2012 - 06:55 AM

This tutorial is the second and final part of Detect User Idle And Do Something After Some Time Ellapsed tutorials. Visit the first part of the tutorial here. The first part explains how to do local user idle detection.


System-Wide User Idle Detection

To detect inactivity of user system wide, we seek the help of Windows API GetLastInputInfo. This api however not available for Windows with
versions prior to Windows 2000. This api is contained in user32.dll. Unfortunately this api is not imported by Delphi default libraries. So we have to import it ourself.

Check the full information about GetLastInputInfo in this msdn page. From the information we get from the page we know that GetLastInputInfo needs a record structure named tagLASTINPUTINFO or LASTINPUTINFO. So we also need to import this structure.

API Imports

The API and related structures are defined as below.



 

BOOL WINAPI GetLastInputInfo(
__out PLASTINPUTINFO plii
);

typedef struct tagLASTINPUTINFO {
  UINT cbSize;
  DWORD dwTime;
} LASTINPUTINFO, *PLASTINPUTINFO;

 


Imported to Delphi, they became:

 

 

interface

type
  PLastInputInfo=^TLastInputInfo;
  {$EXTERNALSYM tagLASTINPUTINFO}
  tagLASTINPUTINFO=record
    cbSize: Integer; // The size of the structure, in bytes. This member must be set to sizeof(LASTINPUTINFO)
    dwTime: Cardinal; // The tick count when the last input event was received.
  end;
  TLastInputInfo = tagLASTINPUTINFO;

{$EXTERNALSYM GetLastInputInfo}
function GetLastInputInfo(var ALastInputInfo: TLastInputInfo): Integer; stdcall;

implementation

function GetLastInputInfo; stdcall; external 'user32.dll'; 

 


Using GetLastInputInfo

From the msdn page, we know that a successfull call to GetLastInputInfo returns a tagLASTINPUTINFO data which contains the tick count of the last time the user of the current session did something. This information is stored in dwTime field of the tagLASTINPUTINFO data.

So, you can use the following code to find how many milliseconds a user has been idle.



 

function GetUserIdleDuration: Cardinal;
var
  vLastInput: TLastInputInfo;
begin
  vLastInput.cbSize := SizeOf(TLastInputInfo);

  if GetLastInputInfo(vLastInput) then
    Result := GetTickCount - vLastInput.dwTime
  else
    Result := 0;
end;

 


Demo Project

For the demo project, create a new application, drop a TTimer, and two TLabel-s. Leave their properties to default values, and arrange them to get something like shown below.

SystemWideUserIdle_Design01.png

  • Double click the TTimer to generate skeleton code of its OnTimer event handler, and use the following codes for the event handler.

    procedure TForm2.Timer1Timer(Sender: TObject);
    var
      vLastInput: TLastInputInfo;
      vIdleTime : Cardinal;
      vHours : Cardinal;
      vMinutes : Cardinal;
      vSeconds : Cardinal;
    begin
      vLastInput.cbSize := SizeOf(TLastInputInfo);
      vLastInput.dwTime := 0;
    
      if GetLastInputInfo(vLastInput) <> 0 then
        vIdleTime := GetTickCount - vLastInput.dwTime
      else
        vIdleTime := 0;
    
      vHours := vIdleTime div (60 * 60 * 1000);
      if vHours > 0 then
        vIdleTime := vIdleTime - (vHours * 60 * 60 * 1000);
    
      vMinutes := vIdleTime div (60 * 1000);
      if vMinutes > 0 then
        vIdleTime := vIdleTime - (vMinutes * 60 * 1000);
    
      vSeconds := vIdleTime div 1000;
    
      Label1.Caption := Format('%.2d:%.2d:%.2d', [vHours, vMinutes, vSeconds]);
    end;
    

     

if you compare the OnTimer code with the one from "Local User Idle Detection", you can see they are very similar. However here we don't need to deal with user become active detection. It is handled by Windows.

Upon running, you will get something like shown below.

SystemWideUserIdle_Run01.png


Note that the counter will reset if you do any activity, no matter on which application you are doing the activity. Even when there is no active application (beside our demo, of course). There! Isn't it easy to detect system wide user idle?

Full source code of the demo project is attached. There you can fully see how the importing C header is done. Feel free to use all or portion of the codes for anything.

Cheers!

Attached Files


Edited by LuthfiHakim, 10 February 2013 - 10:35 AM.

  • 1





Also tagged with one or more of these keywords: timer

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download