Este es un código que ocupo desde hace mucho, no recuerdo de donde lo saqué pero funciona
PUBLIC tmrCheck
tmrCheck = NEWOBJECT("DetectActivity")
DEFINE CLASS DetectActivity as Timer
* Sólo detecta inactividad mientras está en este programa?
JustInThisApp = .F.
* Intervalo de inactividad tras el cual dispara OnInactivity (en segundos)
InactivityInterval = 60 * 15
*InactivityInterval = 60 * 1
* Intervalo cada el que chequea actividad
Interval = 1000
LastCursorPos = ""
LastKeybState = ""
LastActivity = DATETIME()
CursorPos = ""
KeybState = ""
IgnoreNext = .T.
PROCEDURE Init
DECLARE INTEGER GetKeyboardState IN WIN32API STRING @ sStatus
DECLARE INTEGER GetCursorPos IN WIN32API STRING @ sPos
DECLARE INTEGER GetForegroundWindow IN WIN32API
ENDPROC
PROCEDURE Destroy
CLEAR DLLS GetKeyboardState, GetCursorPos, GetForegroundWindow
ENDPROC
PROCEDURE Timer
WITH This
IF ! .CheckActivity()
* Si no hubo actividad veo si es tiempo de disparar OnInactivity
IF ! ISNULL(.LastActivity) AND ;
DATETIME() - .LastActivity > .InactivityInterval
.LastActivity = NULL && Prevengo disparo múltiple de OnInactivity
.OnInactivity()
ENDIF
ENDIF
ENDWITH
ENDPROC
* Chequeo si hay actividad
PROCEDURE CheckActivity
LOCAL lRet
WITH This
IF .JustInThisApp
IF GetForegroundWindow() <> _VFP.hWnd
* Estoy en otro programa
RETURN lRet
ENDIF
ENDIF
.GetCurState()
IF (!.CursorPos == .LastCursorPos OR !.KeybState == .LastKeybState)
IF ! .IgnoreNext && La 1ra vez no ejecuto
lRet = .T. && Hubo actividad
.OnActivity()
.LastActivity = DATETIME()
ELSE
.IgnoreNext = .F.
ENDIF
.LastCursorPos = .CursorPos
.LastKeybState = .KeybState
ENDIF
ENDWITH
RETURN lRet
ENDPROC
* Devuelve el estado actual
PROCEDURE GetCurState
LOCAL sPos, sState
WITH This
sPos = SPACE(8)
sState = SPACE(256)
GetCursorPos (@sPos)
GetKeyboardState (@sState)
.CursorPos = sPos
.KeybState = sState
ENDWITH
ENDPROC
PROCEDURE OnInactivity
IF MESSAGEBOX("El equipo lleva varios minutos sin usarse. Se cerrará la sesión del sistema XXXXXXXXX",4+64+4096,"Cerrando sesión",15000) <> 7
_screen.Tag = ""
If _Screen.FormCount> 0
For i = _Screen.FormCount To 1 STEP -1
_Screen.Forms[i].destroy
_Screen.Forms[i].release
ENDFOR
ENDIF
ENDIF
ENDPROC
PROCEDURE OnActivity
ENDPROC
ENDDEFINE