Solved

Detect user inactivity in a VB.NET Windows Application (multiple forms)

Posted on 2004-10-12
7
6,922 Views
Last Modified: 2012-06-22
I have a large VB.NET application with over 50 forms. There are ~100 functions that require a username and password to commit, and users are finding it a pain to have to continually type their usernames and passwords at each stage.
I want to move to a model that only prompts for a username & password if the application has been inactive (no keyboard of mouse events) for over 3
minutes.
Since I have a large amount of forms and controls, resetting a timer from each individual control is a nightmare. Is there a way of detecting keypress and mouse events across all contols and forms in an application?
I've seen refences to the Application.idle event but no examples on how to call it.

Lanson.
0
Comment
Question by:lanson
7 Comments
 

Expert Comment

by:wayko621
ID: 12286695
A process is said to be idle when its main window is waiting for input from the system. In order to test the process for its idle state, you must first bind a Process component to it. You can call the WaitForInputIdle method before having the target process perform an action.

The WaitForInputIdle method instructs a Process component to wait for the associated process to enter an idle state. The method is useful, for example, when your application waits for a process to finish creating its main window before communicating with that window. The WaitForInputIdle method only works with processes that have a user interface.

To wait for a process to complete an action

Associate an instance of a Process component to a process you want to start. For more information, see Starting Processes.
Start the process by calling the Start method.
Call the appropriate WaitForInputIdle method:
WaitForInputIdle() - instructs the Process component to wait indefinitely for the associated process to enter an idle state.
WaitForInputeIdle(Int32) - instructs the Process component to wait the specified number of milliseconds for an associated process to enter an idle state.
The following example shows how to call the WaitForInputIdle method to wait for Notepad to complete loading before assigning its modules property to an empty array.

' Visual Basic
Dim myProcess as New Process()
myProcess.Start("Notepad.exe")
myProcess.WaitForInputIdle()

// C#
Process myProcess;
myProcess = Process.Start("Notepad");
myProcess.WaitForInputIdle();

maybe this can help =)

You can try the raiseevent also ill get u a code when i test it out
0
 
LVL 28

Accepted Solution

by:
iboutchkine earned 250 total points
ID: 12288955
Private Sub OnApplicationIdle( _
    ByVal sender As Object, ByVal e As System.EventArgs)
i+= 1
       If Time1 > 100 Then
           MessageBox.Show("Application is idle")
           i = 0 ' reset i
       End If

End Sub

To handle the event you must add the event handler.

AddHandler Application.Idle Addressof OnApplicationIdle

0
 
LVL 18

Expert Comment

by:armoghan
ID: 12296074
0
Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

 
LVL 1

Author Comment

by:lanson
ID: 12306943
iboutchkine

Thanks for the info, but I have another question:
1) I tried the code as you supplied it and the idle event is firing constantly while the application is idle. This is fine , if I can find a way to detect a mouse or keyboard event , which I will use to reset the timeout timer. I can't use the keypress events etc as I have thousands of individual controls.
Can I detect what event just finished before the Idle event was called?
(does the e parameter of the function hold this info?)


Regards,
  Lanson.
0
 
LVL 28

Expert Comment

by:iboutchkine
ID: 12308102
Put the timer reset to mouse move event
0
 
LVL 1

Author Comment

by:lanson
ID: 12316850
iboutchkine,
I need to track more than mouse movements, as a lot of the users would be performing data entry using just keyboard and tabs.

I've come up with the following solution:
1) Implement the event handler as you suggested above
2) Use the user32 windows api to detect mouse movement and keypress. The problem with this method is that all mouse movements and keypresses, across all applications are detected, so I use the GetForegroundWindow() and GetWindowText functions of the API to determin if the events happen while my app has focus - ignoring them if it dosn't have focus. All I have to ensure is that the Window Text for all my forms begins with the same Title (e.g MyApp - Main , MyApp - Edit etc)

Example:
 
' Declare form1 as public , as this will hold the idle event code and had to be loaded at all times (can be hidden)

Module Module1

    Public form1 As New form1
    Public intcnt As Integer
    Public LogoutTimer As Date
   
End Module


Public Class Form1

    Inherits System.Windows.Forms.Form
    Public i As Integer
    Public ctrCurr As Control
    Structure POINTAPI
        Public mouseX As Long
        Public mouseY As Long
    End Structure


    Declare Function GetCursorPos Lib "user32" (ByRef lpPoint As POINTAPI) As Integer

    Public Declare Function GetAsyncKeyState Lib "user32.dll" (ByVal vKey As Long) As Integer
    Public Declare Function GetActiveWindow Lib "user32" () As Integer
    Public Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Integer, ByVal lpString As String, ByVal cch As Integer) As Integer
    Public Declare Function GetForegroundWindow Lib "user32" () As Integer

    Public posOld As POINTAPI
    Public posNew As POINTAPI

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load


        ' Associate an event handler with an event.
        AddHandler Application.Idle, AddressOf OnApplicationIdle


    End Sub

   
    Sub OnApplicationIdle(ByVal sender As Object, ByVal e As System.EventArgs)



        Dim x As Long

        x = DateDiff(DateInterval.Minute, LogoutTimer, Now)
        If x > 3 Then
            MsgBox("Timeout!")
            LogoutTimer = Now
        Else

        End If

        Dim foreground_hwnd As Integer

        Dim length As Long

        foreground_hwnd = GetForegroundWindow()

        strWindowText = Space$(1024)
        length = GetWindowText(foreground_hwnd, strWindowText, Len(strWindowText))

        strWindowText = strWindowText.Substring(0, length)

        If InputCheck() Then


            x = DateDiff(DateInterval.Second, LogoutTimer, Now)
            If x > 10 Then
                MsgBox("Timeout!")
            Else
                LogoutTimer = Now

            End If
        End If





    End Sub







 

    Public Function InputCheck() As Boolean
        Dim i As Integer

        'Get the current mouse cursor coordinates
        Call GetCursorPos(posNew)
        'Compare with old coordinates
        'Only flag if the curent window is part of the application MyApp (Window Title)
        If ((posNew.mouseX <> posOld.mouseX) Or (posNew.mouseY <> posOld.mouseY)) And Mid(strWindowText, 1, 5) = "MyApp" Then
            posOld = posNew
            InputCheck = True
            Exit Function
        End If
        'Check keys state
        For i = 0 To 255
            'Only flag if the curent window is part of the application MyApp (Window Title)
            If (GetAsyncKeyState(i) And &H8001) <> 0 And Mid(strWindowText, 1, 5) = "MyApp" Then
                InputCheck = True
                Exit Function
            End If
        Next i
        InputCheck = False
    End Function





End Class

'This Function detects any movement/keypress within the application

    Public Function InputCheck() As Boolean
        Dim i As Integer

        'Get the current mouse cursor coordinates
        Call GetCursorPos(posNew)
        'Compare with old coordinates
        'Only flag if the curent window is part of the application MyApp (Window Title)
        If ((posNew.mouseX <> posOld.mouseX) Or (posNew.mouseY <> posOld.mouseY)) And Mid(strWindowText, 1, 5) = "MyApp" Then
            posOld = posNew
            InputCheck = True
            Exit Function
        End If
        'Check keys state
        For i = 0 To 255
            'Only flag if the curent window is part of the application MyApp (Window Title)
            If (GetAsyncKeyState(i) And &H8001) <> 0 And Mid(strWindowText, 1, 5) = "MyApp" Then
                InputCheck = True
                Exit Function
            End If
        Next i
        InputCheck = False
    End Function





0
 
LVL 15

Expert Comment

by:x77
ID: 33883615
There are some methods to handle Hook to Keyboard / mouse events, but this is very complex.
You have many forms on your app, and you do´nt want recode each form to detect mouse / keyboard activity.

I think you can write a simple class AppForm that detects activity (mouse / keyboard) overriding OnMouseMove and ProcessDialogKey.

You ca set a global var to time action is generated.
Note that time compsuption for this code is minimal.

Then on Application idle event you verify  

    If (Now - GlobalLastKeyboardMouseAction).TotalMinutes > 20 Then
        --- Write Code for Time exceded Here

Now you can change for each form from
    Inherites System.Windows.Form
to
    Inherits AppForm  
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Since .Net 2.0, Visual Basic has made it easy to create a splash screen and set it via the "Splash Screen" drop down in the Project Properties.  A splash screen set in this manner is automatically created, displayed and closed by the framework itsel…
It’s quite interesting for me as I worked with Excel using vb.net for some time. Here are some topics which I know want to share with others whom this might help. First of all if you are working with Excel then you need to Download the Following …
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…
This video discusses moving either the default database or any database to a new volume.

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now