WinBatch Tech Support Home

Database Search

If you can't find the information using the categories below, post a question over in our WinBatch Tech Support Forum.

TechHome

How To
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus

Can't find the information you are looking for here? Then leave a message over on our WinBatch Tech Support Forum.

Exit if PC is Idle


I was looking for a way to log off a PC if the machine "sat idle", i.e. had no mouse or keyboard use. Searching through the WinBatch BBS provided the key steps of looking for changes in the keyboard buffer and mouse position. I implemented this in the attached code, designed to be compiled and run (with optional controlling parameters) at logon time. I am posting it here as a way of saying "Thank you" for the help and ideas I get from here.
;Routine to exit user if computer is idle

;Governed by MaxIdleTime definition, below

; B Schor

; Original version had everything hard-coded
; This version is a bit more flexible
; It follows some of the logic of the MapShares routines

; Designed to be run at logon time

; This routine takes optional switches.

; The following switches are supported:
;   /L:nn   Force Logout after nn minutes
;   /V   Verbose, display run-time dialog box
;   /?   Help

; Be sure to compile as "Hidden" to prevent user from noticing it on taskbar

; 19 Jan 05   First incarnation
; 07 Aug 05   Upgrade, becomes Version 1.00
; 07 Aug 05   Compile as "Hidden", allow exit without query
; 07 Aug 05   Allow 0, negative times to exit immediately
; 16 Sep 05   Use ShowVersionTime
; 10 Oct 05   Version 1.01, implement switches, only let first copy run
; 18 Oct 05   Version 1.02; use if .. then form, "continue" to "flatten" IFs
; 27 Nov 05   Version 1.03; Help switch


; The function below provides help, then exits

#DefineFunction GetHelp (VersionName)

HelpMsg = "Usage: ExitIfIdle {/L:nn} {/V} {/?}"
HelpMsg = StrCat (HelpMsg, @CRLF, @CRLF, "Forces logoff of user if PC seems idle for period of time")
HelpMsg = StrCat (HelpMsg, @CRLF)
HelpMsg = StrCat (HelpMsg, @CRLF, "/L:nn", @TAB, "Optional switch, Logoff Idle Time, nn minutes")
HelpMsg = StrCat (HelpMsg, @CRLF, "/V", @TAB, "Optional Verbose switch")
HelpMsg = StrCat (HelpMsg, @CRLF, "/?", @TAB, "Optional Help switch (this message)")

Message (VersionName, HelpMsg)

; Exit now

Exit

#EndFunction

; --------------------------------------------------------

; The following function returns the state of the (virtual) keyboard buffer
; If it doesn't change, then the user (probably) isn't typing

; Returns a 256-byte buffer

#DefineFunction GetKeyboardState(KbdBuf, BufSize)

; Initially wait for keyboard to be idle

   IntControl (80, 0, 0, 0, 0)

   WinSysDir = DirWindows(1)
   DLLName = StrCat (WinSysDir, "USER32.DLL")

; GetKeyboardState is called with a pointer to the buffer

   DllCall (DLLName, long:"GetKeyboardState", lpbinary:KbdBuf)

; Set the EndOfData value of the buffer

   BinaryEodSet (KbdBuf, BufSize)

   Return KbdBuf

#EndFunction


; --------------  Main Routine starts here ---------------

; Initialize some variables

VersionNum = "1.03"
ShowVersionTime = 2
KbdBufSize = 256
DefaultIdleMinutes = 20

; Use tab as text file delimiter

Delim = @TAB

; Need networking functions

AddExtender ("WWWNT34i.DLL")

; Determine name of logged-on user

SysInfo = WinSysInfo()
UserName = wntGetUser (@DEFAULT)

; Determine name of running program and path

WinBatchProgPathName = 1004

FullSelf = IntControl (WinBatchProgPathName, 0, 0, 0, 0)
SelfPath = FilePath (FullSelf)
SelfName = FileRoot (FullSelf)
SelfExtn = FileExtension (FullSelf)

VersionName = StrCat (SelfName, " ", VersionNum)

Computer = ItemExtract (1, SysInfo, Delim)

; Initialize switch variables to default values

LogoffInterval = DefaultIdleMinutes
VerboseSwitch = @FALSE
AskForHelp = @FALSE

; Parse all parameters, switches

For i = 1 To param0

   ; Get parameter or switch

   ThisParam = param%i%

   ; Locate possible "/".
   ; If first character, treat as switch.  Otherwise, ignore.

   SlashIndex = StrIndex (ThisParam, "/", 1, @FWDSCAN)

   ; Process switch, or ignore

   If SlashIndex == 1
      SwitchChar = StrUpper (StrSub (ThisParam, 2, 1))
      ColonIndex = StrScan (ThisParam, ":", 0, @FWDSCAN)
      If SwitchChar == "V" Then VerboseSwitch = @TRUE
      If SwitchChar == "?" Then AskForHelp = @TRUE
      If ColonIndex <  3   Then Continue
      If SwitchChar == "L" Then LogoffInterval = StrSub (ThisParam, ColonIndex+1, -1)
   EndIf

Next

; Force time intervals to be non-negative

If LogoffInterval < 0 Then LogoffInterval = 0

; Display some self-information, version number if requested

If VerboseSwitch && (ShowVersionTime > 0)
   Msg = StrCat (UserName, ", ", Computer, @CRLF)
   If LogoffInterval > 0
      If LogoffInterval == 1 Then TimeFrame = " minute"
                             Else TimeFrame = " minutes"
      LogoffMsg = StrCat ("Will log off user if idle for ", LogoffInterval, TimeFrame, @CRLF)
   Else
      LogoffMsg = StrCat ("Will not log off user", @CRLF)
   EndIf
   Display (ShowVersionTime, VersionName, StrCat(Msg, LogoffMsg))
EndIf

; Allow routine to exit without errors

ExitOK = 12
AllowExit = 1

IntControl (ExitOK, AllowExit, 0, 0, 0)

; Get help if requested

If AskForHelp Then GetHelp (VersionName)

; Exit if user specifies 0 or negative time parameter

If LogoffInterval <= 0 Then Exit

; How many copies are running?

WinList = WinItemizeEx (StrCat ("~", SelfName, ".exe"), @TRUE, @TRUE)
WinN = ItemCount (WinList, Delim)

; If this is a second (or higher) copy, exit

If WinN > 1
        If VerboseSwitch Then Display (5, VersionName, StrCat ("Exiting -- ", SelfName, " already running"))
        Exit
EndIf

; Now allocate buffers

KbdBuf = BinaryAlloc (KbdBufSize)

; Once a minute, take a snapshot of the mouse and keyboard buffer

; If they've changed, reset the clock and remember the values
; If they're the same, let the clock tick

InitialKbdState = GetKeyboardState (KbdBuf, KbdBufSize)

InitialMouseCoord = MouseInfo (2)

IdleMinutes = 0

; Add one more pass through this loop, a kind of "last chance" to stay live

While IdleMinutes <= LogoffInterval

; Wait a minute or display "final warning", as appropriate

   If IdleMinutes < LogoffInterval
      TimeDelay (60)
   Else
      Beep
      Display (30, VersionName, "Logging off idle PC")
   EndIf

; Get keyboard and mouse states, see if they seem to be untouched

   CurrentKbdState = GetKeyboardState (KbdBuf, KbdBufSize)
   KeyboardUntouched = BinaryCompare (InitialKbdState, 0, CurrentKbdState, 0, KbdBufSize)
   CurrentMouseCoord = MouseInfo (2)
   MouseUntouched = (InitialMouseCoord) == (CurrentMouseCoord)
   If KeyboardUntouched && MouseUntouched
      IdleMinutes = IdleMinutes + 1
   Else
      IdleMinutes = 0
      InitialKbdState = CurrentKbdState
      InitialMouseCoord = CurrentMouseCoord
   EndIf

EndWhile

; If we get here, we've been idle "long enough" and have issued warning to user

; Free up buffers

BinaryFree (KbdBuf)

; Log out the user

Force = 1
Reboot = 67
Logoff = 66

IntControl(Logoff,0,Force,0,0)

Article ID:   W17000
File Created: 2007:07:03:14:27:32
Last Updated: 2007:07:03:14:27:32