I managed to get the real idle time by installing keyboard and mouse hooks, which has a flag that tells if the source of the trigger was real or not. It works, but its not a nice implementation. I can't believe that Microsoft hasn't thought about implementing a system idle timer for REAL events, like GetLastInputInfo(LastInput)
.
I don't know if there are other inputs sources other then keyboard and mouse... If anyone can help me improve this procedure, it is welcome.
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls;
type
TForm1 = class(TForm)
Panel1: TPanel;
Timer1: TTimer;
Panel2: TPanel;
procedure Timer1Timer(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
TrueLastInput: DWORD;
implementation
{$R *.dfm}
const
LLKHF_INJECTED = $00000010;
LLKHF_LOWER_IL_INJECTED = $00000002;
LLMHF_INJECTED = $00000001;
LLMHF_LOWER_IL_INJECTED = $00000002;
type
TLowLevelInputProc = function(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
PKBDLLHOOKSTRUCT = ^TKBDLLHOOKSTRUCT;
TKBDLLHOOKSTRUCT = record
vkCode: DWORD;
scanCode: DWORD;
flags: DWORD;
time: DWORD;
dwExtraInfo: ULONG_PTR;
end;
PMOUSEHOOKSTRUCT = ^TMOUSEHOOKSTRUCT;
TMOUSEHOOKSTRUCT = record
pt: TPoint;
mouseData: DWORD;
flags: DWORD;
time: DWORD;
dwExtraInfo: ULONG_PTR;
end;
var
KHook, MHook: HHOOK;
function KeyboardProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
var Info: PKBDLLHOOKSTRUCT;
begin
if nCode >= 0 then begin
Info:= PKBDLLHOOKSTRUCT(lParam);
if (Info.flags and (LLKHF_INJECTED or LLKHF_LOWER_IL_INJECTED)) = 0 then
TrueLastInput:= Info.time;
end;
Result:= CallNextHookEx(KHook, nCode, wParam, lParam);
end;
function MouseProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
var Info: PMOUSEHOOKSTRUCT;
begin
if nCode >= 0 then begin
Info:= PMOUSEHOOKSTRUCT(lParam);
if (Info.flags and (LLMHF_INJECTED or LLMHF_LOWER_IL_INJECTED)) = 0 then
TrueLastInput:= Info.time;
end;
Result:= CallNextHookEx(MHook, nCode, wParam, lParam);
end;
procedure InstallInputHooks;
var LLKeyboardProc, LLMouseProc: TLowLevelInputProc;
begin
LLKeyboardProc:= @KeyboardProc;
KHook:= SetWindowsHookEx(WH_KEYBOARD_LL, @LLKeyboardProc, HInstance, 0);
LLMouseProc:= @MouseProc;
MHook:= SetWindowsHookEx(WH_MOUSE_LL, @LLMouseProc, HInstance, 0);
end;
procedure UninstallInputHooks;
begin
if KHook <> 0 then begin UnhookWindowsHookEx(KHook); KHook:= 0; end;
if MHook <> 0 then begin UnhookWindowsHookEx(MHook); MHook:= 0; end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
InstallInputHooks;
TrueLastInput:= GetTickCount;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
UninstallInputHooks;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var T0, TD, Tsecs, Tmins: DWORD;
begin
T0:= GetTickCount;
TD:= T0 - TrueLastInput;
Tsecs:= TD div 1000;
Tmins:= Tsecs div 60;
panel2.caption := 'T0='+IntToStr(T0)+' T1='+IntToStr(TrueLastInput)+' TD='+IntToStr(TD)+' secs='+IntToStr(Tsecs)+' mins='+IntToStr(Tmins);
end;
end.