1

Here's what I'm trying to do. I have a LogIn form that will activate/enable a timer when user successfully logs in. I will keep the form in the background and have the timer set to 30 minutes. If there is 30 minutes of inactivity, then I will log the user off - displaying to LogIn form. what would be the best way way to determine if there is any activity in the application - which would in that case reset the time to DateTime.Now(). I was thinking of using these events in each of the forms?

MouseClick
MouseDown
KeyPress
KeyDown

Does vb.net have anything that could make this easier? I came across

GETUSERINPUT 

But I'm not sure if this would work in this case? Since user might not be inputting any new data, but might be simply looking over a record or something?

EDIT:

I created a Timer in my app and I'm trying to find a different between time so that I can display a message box and show that so much time has elapsed. On button click I do this...

dim MyTime as date = DateTime.Now()
Private Sub Button4_Click_1(sender As Object, e As EventArgs) Handles Button4.Click

    MyTime = DateTime.Now()
    Timer1.Interval = 1000

End Sub

Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick

    If DateDiff("n", DateTime.Now(), MyTime) > 1 Then

        MsgBox("TimesUP")
    End If

End Sub

I'm displaying both MyTime and DateTime.Now() and "n" or DateInterval.Minutes both don't work. WHY ???!??!

BobSki
  • 1,531
  • 2
  • 25
  • 61
  • Did you try GETUSERINPUT or anything else? Post what you've tried so far. – apesa Dec 02 '16 at 17:34
  • @plutonix - I like that. I was also thinking something like DateDiff("n", DateTimeSet, Now()) > 30. Where datetimeset = datetime.Now() – BobSki Dec 02 '16 at 17:37
  • I am curious as to this reinventing the wheel - cant the network admin set the systems to log off/sleep the user after 30 mins? Why is this an app function? – Ňɏssa Pøngjǣrdenlarp Dec 02 '16 at 17:39
  • @plutonix - old school shop – BobSki Dec 02 '16 at 17:40
  • 1
    If the log out thing is important, use a stopwatch - users cant fiddle with it. – Ňɏssa Pøngjǣrdenlarp Dec 02 '16 at 17:40
  • `old school shop` doesnt really address the issue - Windows can do this for you automatically – Ňɏssa Pøngjǣrdenlarp Dec 02 '16 at 17:42
  • If you do it locally, you will have to hook up at least all your major container controls to for the mousemove reset – Ňɏssa Pøngjǣrdenlarp Dec 02 '16 at 19:05
  • @plutonix - I see your solution - it's so damn good. but what if I just did it for the form events - and used the code in my edit - but i can't get the stupid dateDiff towork - it only works if I use the text from label as datetime.parse(label1.text) – BobSki Dec 02 '16 at 19:06
  • As I said, use a stopwatch so the users cant spoof it; it will calculate the elapsed for you – Ňɏssa Pøngjǣrdenlarp Dec 02 '16 at 19:09
  • 1
    http://stackoverflow.com/a/12641376/17034 – Hans Passant Dec 02 '16 at 19:12
  • Re your question regarding your original code not working - it's because you just read MyTime once, rather than reading it every tick – peterG Dec 02 '16 at 19:57
  • @peterG well what I was trying to do it on this buttonClick - set MyTime - to dateTime.Now() and then if user does nothing else then once it reaches one minute it would log them off -- but what i was trying to do is for each form mousemove,mousepress, etc events to set MyTime = datetime.Now() and go from there – BobSki Dec 02 '16 at 20:05

1 Answers1

1

I should think a network policy to lock the desktop after a perips of inactivity would be the simplest: no need to save any data (as per a previous question).

Since you are emulating the Windows job of tracking the idle time, you could use the API to get the idle time:

Partial Friend Class NativeMethods
    <StructLayout(LayoutKind.Sequential)>
    Structure LASTINPUTINFO
        <MarshalAs(UnmanagedType.U4)>
        Public cbSize As Integer
        <MarshalAs(UnmanagedType.U4)>
        Public dwTime As Integer
    End Structure 

    ' Gets the time of the last user input in ms
    <DllImport("user32.dll")>
    Private Shared Function GetLastInputInfo(ByRef plii As LASTINPUTINFO) As Boolean
    End Function

    Friend Shared Function GetLastInputTimeElapsed() As Int32
        Dim lastInputInf As New LASTINPUTINFO()
        lastInputInf.cbSize = Marshal.SizeOf(lastInputInf)
        lastInputInf.dwTime = 0

        ' get time of last input, subtract current ticks
        If GetLastInputInfo(lastInputInf) Then
            ' conver to seconds
            Return (Environment.TickCount - lastInputInf.dwTime) \ 1000
        Else
            Return 0
        End If
    End Function
 ...

Then just check the elapsed seconds (or minutes) in a long timer:

Private Sub Timer2_Tick(sender As Object, e As EventArgs) Handles Timer2.Tick

    ' Gets the time of the last user input in ms
    Dim elapsed = NativeMethods.GetLastInputTimeElapsed()

    ' 45 sec TimeOut for testing
    If elapsed > 45 Then
        Label3.Text = "You're done!"
    Else
        Label3.Text = String.Format("Idle for: {0} secs", elapsed)
    End If
End Sub

Animated GIFs dont run fast enough to show, but input is detected in the form of any mousemove or keypress. Note that this detects system input - mouse moves and key pressed with your app minimized will count. This makes some sense - if the app is minimized and times itself out, I'd be suprised to see it just disappear. If I am totally AFK, thats another thing.


Local Timer

For a simple form, the answer for VB Detect Idle time is pretty simple: it stops and restarts your 30 min timer whenever it sees a mousemove or keypress. It doesnt detect movement on container controls though.

Using a Stopwatch will work too:

' form/class level
Private swLogout As Stopwatch

' start it with the app:
swLogout = New Stopwatch()
swLogout.Start()

You need to restart it for each keypress and mousemove. For the first, set KeyPreview to true, then:

Private Sub MainFrm_KeyPress(sender As Object, 
          e As KeyPressEventArgs) Handles MyBase.KeyPress
    swLogout.Restart()
End Sub

Mousemove is more problematic, you need to hook up all the major container controls:

Private Sub MainFrm_MouseMove(sender As Object, 
            e As MouseEventArgs) Handles MyBase.MouseMove,
                  TabControl1.MouseMove, TabControl2.MouseMove,
                  ..., TabPage12.MouseMove
    swLogout.Restart()
End Sub

Then check the elapsed time in a fairly short timer (like 3 mins maybe):

Private Sub Timer2_Tick(sender As Object, e As EventArgs) Handles Timer2.Tick
    Dim elapsed = swLogout.ElapsedMilliseconds \ 1000

    ' demo == 3 secs
    If elapsed > 3 Then
        Label3.Text = "You're done!"
        Timer2.Enabled = False
    Else
        Label3.Text = String.Format("Idle for: {0} secs", elapsed)
    End If
End Sub
Community
  • 1
  • 1
Ňɏssa Pøngjǣrdenlarp
  • 38,411
  • 12
  • 59
  • 178